home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 21
/
Aminet 21 (1997)(GTI - Schatztruhe)[!][Oct 1997].iso
/
Aminet
/
mus
/
midi
/
MusicXMagic.lha
/
MusicX-Magic.txt
< prev
next >
Wrap
Text File
|
1997-07-11
|
25KB
|
642 lines
Music-X Magic:
Soup Up Your Sequencer With ARexx
Copyright 1994 by Daniel J. Barrett
Email: dbarrett@ora.com
*** This article may be freely distributed, as long as it ***
*** is distributed in its entirety, without modification. ***
After a several year wait between updates, Music-X 2.0 finally
arrived last Spring. One of the significant changes is that the program
now supports ARexx, the Amiga's inter-program communication language. This
is very good news: you can now extend Music-X's capabilities in powerful
ways by writing "scripts" that operate on your sequences. For example,
scripts can count the number of musical events in a sequence, transpose
your music in various ways, or perform algorithmic composition. You can
even make Music-X communicate with other ARexx compatible programs (more
than 400 exist) to increase your power even further. For example, you can
send data from Music-X directly into Deluxe Music 2.0 for musical notation,
or communicate with a statistical package to analyze your sequences.
Unfortunately, the ARexx documentation for Music-X is very sketchy.
The manual is brief, omits some vital facts, and the example scripts
mentioned in the manual (page 22) were omitted from the program. This
article clarifies the manual, reveals the missing information, and teaches
you how to write several useful scripts. This article assumes that you
have at least looked at the ARexx chapter of the upgrade manual; keep it
nearby for reference.
A MOTIVATING EXAMPLE
Let's begin with a simple script that transposes all the notes in
your sequence upward by a perfect fifth (7 semitones). The numbers 1-12 on
the left side are not part of the script; they are for our reference only.
1 /* Transpose up by a perfect fifth. */
2 OPTIONS RESULTS
3 BeginScan ALL
4 NextEvent
5 DO WHILE RESULT = 1
6 IF Event.Type = "NOTE" THEN DO
7 Event.Num = Event.Num + 7
8 ReplEvent
9 END
10 NextEvent
11 END
12 EndScan
Let's examine what each line means.
1. A comment. Every ARexx script must begin with a comment;
this is required, or else the script will not work.
2. Tell ARexx to report the results of certain commands in
a variable called "RESULT". We need this variable on
line 5.
3. Tell Music-X that we want to examine (scan through) all
the events in the current sequence.
4. Read the first event. Its data is automatically stored in
a special variable called "Event".
5-11. This "loop" is the heart of the script. As each event is
read, its type is checked. If it is a NOTE event, add 7 to
its note number, and use "ReplEvent" to make the change
permanent. No matter what, we move to the next event and
repeat. When there are no more events, "NextEvent" will
fail, RESULT will equal zero (meaning failure), and the
loop ends.
12. Tell Music-X we are done scanning the sequence.
Type this script into a file called "Transposer.mxe". Now load
a sequence into the Bar Editor, choose "Rexx..." from the Modules menu,
use the file requestor to locate your Transposer.mxe script, and double-click
on the script name. Voila! Your notes have been transposed.
BASIC CONCEPTS
ARexx support in Music-X is handled by a new module called
RexxEdit. This module is automatically installed when you use the Music-X
installation program. However, due to a bug in the installation, all your
modules may not be accessible due to incorrect path names. If you
encounter this, then exit Music-X, run the "Install Modules" program, click
on each module name and remove the leading colon ":" from its Path, choose
"Save", and restart Music-X.
In a nutshell, RexxEdit allows you to do four kinds of operations:
1. Examine, add, delete, and change data in sequences.
2. Display requestors with a variety of gadgets for user input.
3. Get information about the bar editor: grid size,
selected regions, step size, etc.
4. Communicate with other ARexx-compatible programs.
In addition, RexxEdit does NOT allow you to:
1. Control recording and playback.
2. Control the Tool List in the Bar and Event Editors.
3. Use the cut, copy, and paste features.
4. Display or hide events in the Bar and Event Editors.
5. Affect the controls on the Sequencer, Filters, Samples, and
Librarian pages.
Perhaps a later version of Music-X will support such operations; but given
how long it took for the 2.0 update, I have my doubts.
OPERATIONS ON SEQUENCES
Scripts that operate on sequences typically look a lot like
our "Transposer.mxe" example. First, BeginScan must be called to examine
the sequence. This is followed by a loop which examines each event using
NextEvent and processes it in some way. When NextEvent returns "0" in the
RESULT variable, the loop is finished, and we call EndScan.
If you plan to add events to a sequence using AddEvent, there is
an undocumented step which you MUST do: initialize the "Event" variable.
This is done by placing the line
Event. = ""
once in your script, before any call to AddEvent. Note that the
period after "Event" is mandatory because it is a stem variable. It
doesn't matter what value you assign here; for example,
Event. = 192873
will work equally well.
As an example, let's modify Transposer.mxe so instead of moving
the notes, it adds new notes 7 semitones above the originals. For
example, every C will get a new G added above it. This requires two
changes: initialize the "Event" variable (say, between lines 2 and 3),
and change the ReplEvent on line 8 to AddEvent. Store the script in a new
file called Interval.mxe and test it out.
REQUESTORS AND USER INPUT
Our Transposer.mxe script is useful but limited. What if you want
to transpose notes by sevenths instead of fifths? Do we need a whole new
script for every kind of transposition? Nope! In this section, we will
add a requestor to Transposer.mxe with several gadgets, allowing user
control over the script's behavior.
RexxEdit can display three kinds of requestors: a file requestor
(MXFile), a "tell the user" requestor (MXReport), and a gadget-filled
requestor for user input (MXRequest). The first two are well explained on
page 46 of the upgrade manual. Our example will use the more complicated
MXRequest. There are four steps to using it:
1. Decide whether you want a 1-column or 2-column requestor,
using the MXColumn command. (Optional.)
2. Define your gadgets. Your choices are:
MXButton On/Off buttons.
MXSlider Sliders with positive values.
MXMirror Sliders with negative and positive values.
MXString String gadgets for text input.
MXNoteSize The Music-X note duration control.
MXLabel Plain text; not for user input.
3. Display the requestor with the MXRequest command.
4. Read the gadgets with the MXValue command to find out the user's
selections.
Our example lets the user choose a transposition interval, whether
to replace or add notes, and whether to affect all notes or just
selected/marked notes. First, let's design the requestor.
1 /* A requestor for transposing. */
2 OPTIONS RESULTS
3 MXMirror "Semitones:,127"
4 MXRadio "Replace existing notes,Add new notes"
5 MXRadio "All notes,Selected notes only"
6 MXRequest "My Transposer"
Lines 3-5 define three gadgets: a "Semitones" slider running from -127 to
+127, a pair of buttons for choosing replace or add, and another pair of
buttons for choosing all or selected notes. Line 6 actually displays the
requestor with our gadgets, as shown in Figure 1. To display it yourself,
save lines 1-5 in a script called "Requestor.mxe" and execute it. Play
around with the gadgets all you like, but remember that this requestor will
have no actual effect on your sequence... yet.
Continuing, let's find out what the user chose to do. If the
user clicked CANCEL, the RESULT variable will have value 0. If so,
we choose to exit immediately:
7 IF RESULT = 0 THEN
8 EXIT
Next, we check our three defined gadgets using MXValue. To read the
first gadget, use "MXValue 1"; for the second, "MXValue 2"; etc. The gadget
value is returned in the RESULT variable. For "Semitones" slider, we store
the results in a variable "semitones":
9 MXValue 1
10 semitones = RESULT
The "add/replace" radio buttons have value 0 if the first button was
chosen, or a 1 for the second button:
11 MXValue 2
12 add = RESULT
For the "all/selected events" buttons, we set the variable "scanType" to
"ALL" or "SELECTED" appropriately. These words have special value for
the BeginScan command later:
13 MXValue 3
14 IF RESULT = 0 THEN
15 scanType = "ALL"
16 ELSE
17 scanType = "SELECTED"
Save lines 1-17 in a file called "Requestor2.mxe", execute it, play with
the gadgets, and see what happens.
Now we are done with gadgets and user input, so it's time to do
the actual transposition.
18 Event. = ""
19 BeginScan scanType
20 NextEvent
21 DO WHILE RESULT = 1
22 IF Event.Type = "NOTE" THEN DO
23 Event.Num = Event.Num + semitones
24 IF add = 1 THEN
25 AddEvent
26 ELSE
27 ReplEvent
28 END
29 NextEvent
30 END
Note how similar this is to the loop in Transposer.mxe. The only
differences are in lines:
18. Initialize the Event variable so we can add events.
19. BeginScan is instructed to scan ALL or SELECTED events,
based on the user choice.
23. We now add the value "semitones" instead of 7.
24-27. Depending on the user's choice, we either add or replace
the notes we transpose.
Put lines 1-30 in a file called NewTransposer.mxe, and have fun
with this highly useful script! If you try to transpose notes higher than
MIDI allows (127), Music-X will "wrap then around" to 0 again; similarly
for note numbers below 0. A note of caution: this script has very little
error checking. You really should check the value of RESULT after the
BeginScan, AddEvent, and ReplEvent commands to make sure they worked.
EXAMINING THE BAR EDITOR
In this section, we will build a script for adding pitch bend to a
marked or selected region. Pitch bend events will be added, one at a time,
at regular intervals in the region. The user may define how far apart
the pitch bend events are. When followed by Music-X's Sculpt tool, this
script will let you create interesting pitch-bend shapes.
Bar Editor information is examined by using the GetBarData command.
This command fills in the variable "BarData" with information like the
current grid size, measure size, beginning and end of a marked region, etc.
GetBarData is used like this:
1 /* Bar Data example with pitch bend events. */
2 OPTIONS RESULTS
3 GetBarData
4 IF RESULT = 0 THEN DO
5 MXReport "Could not get bar data."
6 EXIT
7 END
Next, we detect whether there is a region defined.
8 IF BarData.Select = "NONE" THEN DO
9 MXReport "No region is marked/selected."
10 EXIT
11 END
Save lines 1-11 to a file called "CheckRegion.mxe" and execute it.
If no region is marked or selected, the script will display the MXReport
requestor.
Next, we allow the user to choose the spacing between the pitch
bend events, using an MXNoteSize gadget, and the MIDI channel for the
events, using a slider gadget. We store the user's choices in the
variables "spacing" and "midiChannel", respectively.
12 MXNoteSize "Set Spacing:"
13 MXSlider "MIDI Channel:,1,16,1"
14 MXRequest "Add Pitch Bend Events"
15 IF RESULT = 0 THEN
16 EXIT
17 MXValue 1
18 spacing = RESULT
19 MXValue 2
20 midiChannel = RESULT - 1
The reason for "RESULT - 1" is that Music-X stores MIDI channels 1-16
as 0-15 internally. Add lines 12-20 to your script so you can see the
requestor in Figure 2.
Next, we locate the beginning and end of the region. Time in
Music-X is measured in bars (measures) and clocks (clock ticks in each
measure). For example, a note might appear in bar 17, clock 2475.
Information about bars and clocks is stored in the variables:
BarData.Start.Bars Measure number of the start of the region.
BarData.Start.Clocks Clock number of the start of the region.
BarData.Stop.Bars Measure number of the end of the region.
BarData.Stop.Clocks Clock number of the end of the region.
BarData.Measure Number of clocks per measure.
We use our own variable "currentTime" to represent the current
location in the region as we add events. As the script progresses, we
repeatedly add a number of clocks (stored in the "spacing" variable) to the
current time. However, when adding an event, we need to know the Bars and
Clocks values, which will require a little math.
Given the measure number and clock number of a Music-X event, the
formula for calculating its location in clocks is:
(Measure number) * (Clocks per Measure) + (Clock number)
Thus, in our script, we compute the starting and ending times of our
region, in clocks:
21 currentTime = BarData.Start.Bars * BarData.Measure ,
+ BarData.Start.Clocks
22 endTime = BarData.Stop.Bars * BarData.Measure ,
+ BarData.Stop.Clocks
(Note: In ARexx, a comma means "continued on the next line." If you can
fit each command on one line -- not possible on this magazine page -- then
you must omit the commas.)
Next, we prepare to scan the region. Just for fun, while the
script is working, we change the pointer to the "sleeping cloud" to
indicate work is being done.
23 MXPointer "SLEEPY"
24 Event. = "" /* Initialize Event variable */
25 BeginScan
Since we are adding pitch bend events, we can fill in some of
the Event variable fields that will remain constant: the event type,
the MIDI channel, and an event value (we choose +8192, which is zero
pitch bend).
26 Event.Type = "PBEN"
27 Event.Channel = midiChannel
28 Event.Num = 8192
Finally, it is time to add pitch bend events! To add them at the
right locations, we must calculate the Bar and Clock numbers where they
should be added. The bar number is obtained using integer division (the
"%" operator), and the clock number using the "mod" or "remainder" function
(the "//" operator):
29 DO WHILE currentTime <= endTime
30 Event.Start.Bars = currentTime % BarData.Measure
31 Event.Start.Clocks = currentTime // BarData.Measure
32 AddEvent
33 currentTime = currentTime + spacing
34 END
When the loop is done, clean up and exit.
35 EndScan
36 MXPointer "NORMAL"
Save lines 1-36 in a file called "PitchBend.mxe". To use this
script, first mark a region or select some events. Second, run the
PitchBend.mxe script. Third, use the Sculpt Tool to shape the pitch bend
events the way you want them. Enjoy!
Note: RexxEdit has a bug concerning marked regions. If a region
appears to be marked, but you keep getting the requestor "No region is
marked/selected," try marking the region again or using the Select tool
instead of Mark. (See "TECH TALK" below for more information.)
Another note: the above assumes you are using "relative time"
sequences, not "absolute time" sequences. If you use absolute time
sequences, then time is measured in quarter frames instead of clocks;
see the manual for more information.
COMMUNICATING WITH OTHER PROGRAMS
Using the ARexx "ADDRESS" command, Music-X scripts can talk to
other ARexx-compatible products such as Deluxe Music 2.0, Bars and Pipes
Professional, One Stop Music Shop, and even non-music products. How about
using SuperBase Professional to store your Music-X sequences? VLT for
uploading and downloading sequences? AmigaVision for multimedia? The
possibilities are numerous and exciting.
Communicating with another program has 4 steps.
1. Find out the ARexx port names of the other program, by
consulting its documentation.
2. Store Music-X's port name in a variable for safekeeping,
using the Address() command. (See "TECH TALK", below,
if you are interested in the reason.)
3. Use the Show("P") command to make sure that the other programs
are running. If not, then your script run them, using the
"WaitForPort" command to wait until the program is running.
4. Use the "ADDRESS" command to talk to the other programs.
In this section, we write scripts to communicate with Electronic
Arts' Deluxe Music 2.0 notation program, port name "DMUSIC", and Oxxi's
TurboText editor, port name "TURBOTEXT". Our first script sends the
currently selected Music-X note to Deluxe Music, inserting it at Deluxe
Music's current cursor location.
First, we save Music-X's port name in a variable "myAddress":
1 /* Example script using Deluxe Music 2.0. */
2 OPTIONS RESULTS
3 myAddress = Address()
Next, we make sure that something is selected.
4 GetBarData
5 IF BarData.Select ~= "SELECT" THEN DO
6 MXReport "Nothing is selected."
7 EXIT
8 END
Next, we make sure that the selected event is a note.
9 BeginScan "SELECTED"
10 NextEvent
11 EndScan
12 IF Event.Type ~= "NOTE" THEN DO
13 MXReport "You must select a note."
14 EXIT
15 END
Next, we make sure Deluxe Music is running by looking for its
ARexx port. If a port named "DMUSIC" does not exist, then we run
Deluxe Music.
16 IF ~Show('P', 'DMUSIC') THEN DO
17 ADDRESS COMMAND
18 "Run < NIL: > NIL: DMusic"
19 WaitForPort "DMUSIC"
20 END
Now, we are ready to send the note from Music-X to Deluxe Music.
21 ADDRESS "DMUSIC"
22 INSERTITEM NOTE PITCH Event.Num
23 NEXT NOTE
Finally, we pop the Deluxe Music screen to the front to see our
handiwork:
24 SCREENTOFRONT
Save lines 1-24 to a file called "DMusic.mxe", execute the script,
and watch what happens. With some work, this script could be the basis for
a whole direct interface between Music-X and Deluxe Music. You may notice
that we didn't use the myAddress variable. This is because the script did
all its Music-X communication first, and then all its Deluxe Music
communication.
The next example is more complex, sending information about notes
and their velocities from a sequence into a TurboText edit window. We
start off with the usual, saving Music-X's address and invoking TurboText
if it is not running:
1 /* Send note information to TurboText. */
2 OPTIONS RESULTS
3 myAddress = Address()
4 IF ~Show("P", "TURBOTEXT") THEN DO
5 ADDRESS COMMAND
6 "TTX > NIL: BACKGROUND NOWINDOW"
7 WaitForPort "TURBOTEXT"
8 END
Next, we tell TurboText to open a new edit window. The name of
that window (its own ARexx port) is returned in the RESULT variable:
9 ADDRESS "TURBOTEXT"
10 OpenDoc
11 windowName = RESULT
Finally, we talk to Music-X again, scan through the sequence,
picking out notes, and sending their information to the TurboText window:
12 ADDRESS VALUE myAddress
13 BeginScan ALL
14 NextEvent
15 DO WHILE RESULT = 1
16 IF Event.Type = "NOTE" THEN DO
17 ADDRESS VALUE windowName
18 Insert "Note" Event.Num "Vel" Event.Attack
19 InsertLine
20 ADDRESS VALUE myAddress
21 END
22 NextEvent
23 END
24 EndScan
I realize that these Deluxe Music and TurboText scripts are harder
to understand than the previous ones. This is because each program has its
own set of commands, such as "OpenDoc" and "Insert" in the TurboText example.
Writing scripts that connect two programs means learning the command sets for
both programs, and this may require careful reading of each program's
documentation, as well as a lot of hair pulling!
REXXEDIT TIPS AND TRICKS
Here is a set of (mostly undocumented) tips and tricks I've
discovered while writing Music-X scripts.
o The MXReport command is great for helping to debug your scripts.
If you want to see the value of a variable (say, "myVar") at any
time, just insert the line "MXReport myVar" at the appropriate spot
in the script. If you need more space for messages, use MXLabel
and MXRequest.
o If your gadgets in an MXRequest don't have enough space between
them for your tastes, the command
MXLabel ""
will insert a blank line. Remember to count this MXLabel
command when using MXValue to read gadget values!
o By default, the RexxEdit module is available only inside the Bar
and Event Editors. But you can use the "Install Modules" script
to make it available in other pages. Simply click on the
other checkboxes in the "Install Modules" window, quit and
restart Music-X, and you're set. The ARexx functionality will
be more limited on other pages, because there is no "current
sequence" being displayed, but you can still do some interesting
things.
o The "Event" variable has different fields depending on what
type of event it contains. For example, a NOTE event has its
velocity in Event.Attack, but it does not use Event.Pressure.
You must write your scripts carefully so they examine ONLY
the Event fields that apply to the current event. Read pages
49-52 carefully to learn which event fields are valid.
(See also the next item.)
o The spacing and boldfacing on pages 49 and 50 of the Music-X 2.0
Upgrade Manual is messed up, making it difficult to distinguish
event types from variables. Four variable names are incorrectly
boldfaced: EVENT.DEM belongs to the TSIG event, EVENT.TRANSPOSE
and EVENT.CUT belong to the PSEQ event, and EVENT.ATTACK belongs
to the NOTE event.
o The range of pitch bend values goes from -8192 to +8191, with
0 being zero pitch bend. PBEN event values
(Event.Num) are really between 0 and 16383; that
is, 8192 higher than the actual bend value. If you use an MXMirror
gadget to get pitch bend values from the user, remember to
add 8192 to the result before storing it in Event.Num.
o Since pitch bend goes from -8192 to +8191, not +8192. If you use an
MXMirror slider for pitch bend, the highest positive value +8192
is invalid. So your script may need code like this:
MXValue 3 /* Get the MXMirror value. */
value = RESULT
IF value = 8192 THEN /* Disallow +8192 value. */
value = 8191
REXXEDIT PROBLEMS
One of RexxEdit's omissions is that it has no ARexx command for
disabling user input. While a script is running, all gadgets on the Music-X
screen are "live," even though they do not appear to respond, and they will
react to all of your inadvertent keystrokes and mouseclicks when the script
finishes. So, while a script is executing, don't click on any gadgets
except those in an ARexx requestor (e.g., MXRequest). As a visual aid, do
"MXPointer SLEEPY" while a script is running.
Second, RexxEdit cannot abort a script in progress. Suppose your
script scans a sequence with a loop, but you forget to call NextEvent in
it. You now have an infinite loop and no way to stop it except by
rebooting your Amiga.
Third, as mentioned earlier, Music-X "forgets" any marked region
every time RexxEdit is run. This is especially confusing because the
region on the screen still appears to be marked. The problem does not
occur with selected events. To get around this problem, either use
selecting instead of marking when possible, or re-mark the region after
each ARexx macro is run. There is also a problem with the selected
events. The Select tool works fine. However, if you use the Move or Add
tools and click on an event, it highlights as if it were selected. Other
modules like the Quantizer will treat it as selected. However, RexxEdit
does not think it is selected. The moral: if a script requires selected
events, you must use the Select tool.
TECH TALK
If you've used ARexx before, you may notice that Music-X's
interface is unusual in several notable ways. First, its ARexx port name
is completely undocumented. By using the command
MXReport Address()
I discovered that the name is "MUSIC-X AREXX EDIT". However, this
information is of no use, because of a second non-standard feature: it's
impossible to control Music-X from another program. All scripts must be
run from inside Music-X. This is because the ARexx port belongs to
RexxEdit, not to Music-X. When RexxEdit is not running, the port
disappears, and when RexxEdit is running, Music-X occupies its full
attention.
A third oddity involves ARexx return codes. By convention, ARexx
commands return their success (1) or failure (0) values in the "RC"
variable. Music-X uses the "RESULT" variable instead, which is usually
reserved for more complex return values. RC is unused. Until you figure
this out, you'll be scratching your head wondering why your error-checking
doesn't work.
GOOD LUCK!
By using ARexx and RexxEdit, you can personalize Music-X with
powerful new tools of your own invention. It takes some effort to get
used to ARexx, but the results can really be worth it.
===
Daniel J. Barrett has been making electronic and computer music since
1979, and has been an Amiga owner since 1987.